#include "async_http.h"
#include "lwip/tcp.h"
#include "lwip/ip_addr.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

/* 定义异步 HTTP 客户端上下文结构体 */
typedef struct async_http_client {
    struct tcp_pcb *pcb;         // lwIP TCP 控制块
    char *response_buf;          // 用于累积响应数据
    int response_buf_size;       // 当前已接收数据长度
    int response_buf_alloc;      // 分配的缓冲区总大小
    char *request_buf;           // 存放构造好的 HTTP 请求字符串
    int request_len;             // 请求字符串长度
    http_response_callback_t callback; // 用户响应回调函数
    void *cb_arg;                      // 用户传入的上下文参数
} async_http_client_t;

/* 前向声明各个回调函数 */
static err_t http_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err);
static err_t http_client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
static err_t http_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len);
static void  http_client_err(void *arg, err_t err);

/*
 * async_http_request 接口实现：
 * 根据传入的参数构造 HTTP 请求字符串，建立 TCP 连接后发送请求，
 * 通过 lwIP 的回调机制异步接收响应并解析 HTTP 头和 body，
 * 最后调用用户注册的回调函数。
 */
int async_http_request(const char *method, const char *host, uint16_t port,
                       const char *path, const char *extra_headers, const char *body,
                       http_response_callback_t callback, void *cb_arg)
{
    async_http_client_t *client = malloc(sizeof(async_http_client_t));
    if (!client) return -1;
    memset(client, 0, sizeof(async_http_client_t));
    client->callback = callback;
    client->cb_arg = cb_arg;

    /* 初始化接收缓冲区 */
    client->response_buf_alloc = 1024;
    client->response_buf = malloc(client->response_buf_alloc);
    if (!client->response_buf) {
        free(client);
        return -1;
    }
    client->response_buf_size = 0;

    /* 构建 HTTP 请求字符串 */
    int req_len = 0;
    char content_length_header[64] = {0};

    if (strcasecmp(method, "GET") == 0) {
        /* GET 请求格式 */
        req_len = strlen("GET ") + strlen(path) + strlen(" HTTP/1.1\r\n") +
                  strlen("Host: ") + strlen(host) + strlen("\r\n");
        if (extra_headers)
            req_len += strlen(extra_headers);
        req_len += strlen("\r\n"); // 空行结束标识
    }
    else if (strcasecmp(method, "POST") == 0) {
        /* POST 请求格式 */
        req_len = strlen("POST ") + strlen(path) + strlen(" HTTP/1.1\r\n") +
                  strlen("Host: ") + strlen(host) + strlen("\r\n");
        if (body) {
            snprintf(content_length_header, sizeof(content_length_header),
                     "Content-Length: %d\r\n", (int)strlen(body));
            req_len += strlen(content_length_header);
        }
        if (extra_headers)
            req_len += strlen(extra_headers);
        req_len += strlen("\r\n"); // 空行结束标识
        if (body)
            req_len += strlen(body);
    }
    else {
        /* 目前仅支持 GET 和 POST 方法 */
        free(client->response_buf);
        free(client);
        return -1;
    }

    client->request_buf = malloc(req_len + 1);
    if (!client->request_buf) {
        free(client->response_buf);
        free(client);
        return -1;
    }

    /* 拼接请求字符串 */
    if (strcasecmp(method, "GET") == 0) {
        sprintf(client->request_buf, "GET %s HTTP/1.1\r\nHost: %s\r\n", path, host);
        if (extra_headers)
            strcat(client->request_buf, extra_headers);
        strcat(client->request_buf, "\r\n");
    }
    else if (strcasecmp(method, "POST") == 0) {
        sprintf(client->request_buf, "POST %s HTTP/1.1\r\nHost: %s\r\n", path, host);
        if (body)
            strcat(client->request_buf, content_length_header);
        if (extra_headers)
            strcat(client->request_buf, extra_headers);
        strcat(client->request_buf, "\r\n");
        if (body)
            strcat(client->request_buf, body);
    }
    client->request_len = strlen(client->request_buf);

    /* 创建 TCP 控制块 */
    client->pcb = tcp_new();
    if (!client->pcb) {
        free(client->request_buf);
        free(client->response_buf);
        free(client);
        return -1;
    }

    /* 注册回调函数，并将 client 作为参数传递 */
    tcp_arg(client->pcb, client);
    tcp_recv(client->pcb, http_client_recv);
    tcp_err(client->pcb, http_client_err);
    tcp_sent(client->pcb, http_client_sent);

    /* 将 host 字符串解析为 IP 地址 */
    ip_addr_t dest_ip;
    if (!ipaddr_aton(host, &dest_ip)) {
        tcp_close(client->pcb);
        free(client->request_buf);
        free(client->response_buf);
        free(client);
        return -1;
    }

    /* 异步建立 TCP 连接 */
    err_t err = tcp_connect(client->pcb, &dest_ip, port, http_client_connected);
    if (err != ERR_OK) {
        tcp_close(client->pcb);
        free(client->request_buf);
        free(client->response_buf);
        free(client);
        return -1;
    }
    return 0;
}

/* TCP 连接建立成功后的回调 */
static err_t http_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
{
    async_http_client_t *client = (async_http_client_t *)arg;
    if (err != ERR_OK) {
        if (client->callback)
            client->callback(NULL, NULL, 0, client->cb_arg);
        free(client->request_buf);
        free(client->response_buf);
        free(client);
        return err;
    }
    /* 发送构造好的 HTTP 请求 */
    err_t wr_err = tcp_write(tpcb, client->request_buf, client->request_len, TCP_WRITE_FLAG_COPY);
    if (wr_err != ERR_OK) {
        tcp_close(tpcb);
        free(client->request_buf);
        free(client->response_buf);
        free(client);
        return wr_err;
    }
    tcp_output(tpcb);
    return ERR_OK;
}

/* 数据发送完成回调，此处无需额外处理 */
static err_t http_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
    return ERR_OK;
}

/* TCP 数据接收回调：累加接收到的数据，直至连接关闭 */
static err_t http_client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
    async_http_client_t *client = (async_http_client_t *)arg;
    if (p == NULL) {
        /* 当 pbuf 为 NULL 表示对端关闭连接，此时认为响应已接收完毕 */
        if (client->response_buf_size > 0) {
            /* 确保缓冲区最后以 '\0' 结尾，便于后续字符串处理 */
            if (client->response_buf_size >= client->response_buf_alloc) {
                char *tmp = realloc(client->response_buf, client->response_buf_size + 1);
                if (tmp) {
                    client->response_buf = tmp;
                    client->response_buf_alloc = client->response_buf_size + 1;
                }
            }
            client->response_buf[client->response_buf_size] = '\0';

            /* 根据 "\r\n\r\n" 分割 HTTP 响应头和响应体 */
            char *header_end = strstr(client->response_buf, "\r\n\r\n");
            if (header_end) {
                int header_len = header_end - client->response_buf + 4; // 包括 "\r\n\r\n"
                char *header_str = malloc(header_len + 1);
                if (header_str) {
                    memcpy(header_str, client->response_buf, header_len);
                    header_str[header_len] = '\0';
                    char *body_ptr = client->response_buf + header_len;
                    int body_len = client->response_buf_size - header_len;
                    if (client->callback)
                        client->callback(header_str, body_ptr, body_len, client->cb_arg);
                    free(header_str);
                } else {
                    /* 分配失败则直接传递整个缓冲区 */
                    if (client->callback)
                        client->callback(client->response_buf, client->response_buf + header_len,
                                         client->response_buf_size - header_len, client->cb_arg);
                }
            } else {
                /* 没有找到分隔标识，认为整个响应都是头 */
                if (client->callback)
                    client->callback(client->response_buf, NULL, 0, client->cb_arg);
            }
        } else {
            if (client->callback)
                client->callback(NULL, NULL, 0, client->cb_arg);
        }
        tcp_close(tpcb);
        free(client->request_buf);
        free(client->response_buf);
        free(client);
        return ERR_OK;
    }
    else if (err == ERR_OK) {
        /* 累加接收到的数据 */
        if (client->response_buf_size + p->len > client->response_buf_alloc) {
            int new_alloc = client->response_buf_alloc * 2;
            while (new_alloc < client->response_buf_size + p->len)
                new_alloc *= 2;
            char *new_buf = realloc(client->response_buf, new_alloc);
            if (!new_buf) {
                pbuf_free(p);
                tcp_abort(tpcb);
                free(client->request_buf);
                free(client->response_buf);
                free(client);
                return ERR_MEM;
            }
            client->response_buf = new_buf;
            client->response_buf_alloc = new_alloc;
        }
        memcpy(client->response_buf + client->response_buf_size, p->payload, p->len);
        client->response_buf_size += p->len;
        tcp_recved(tpcb, p->len);
        pbuf_free(p);
        return ERR_OK;
    }
    pbuf_free(p);
    return err;
}

/* TCP 错误回调：发生错误时释放所有资源并通知用户 */
static void http_client_err(void *arg, err_t err)
{
    async_http_client_t *client = (async_http_client_t *)arg;
    if (client) {
        if (client->callback)
            client->callback(NULL, NULL, 0, client->cb_arg);
        free(client->request_buf);
        free(client->response_buf);
        free(client);
    }
}
